/*-------------------------------------------------------------------------

***************** Modification History ***********************************
   @doc
   @module Entry.c - Data entry functions |
   @end
   
$Log: /SoftPay/SPK2SIM/Source/Ui/entry.c $ 
**************************************************************************

   Copyright (C) 1999 by VeriFone, Inc.

   All rights reserved.  No part of this software may be reproduced,
   transmitted, transcribed, stored in a retrieval system, or translated
   into any language or computer language, in any form or by any means,
   electronic, mechanical, magnetic, optical, chemical, manual or otherwise,
   without the prior written permission of VeriFone, Inc.

---------------------------------------------------------------------------*/
#define VSENTRY_C

#include <project.h>

//#include <beetle.h>
//#include <beetleplug.h>

#include <aclconio.h>
#include <string.h>
#include <applidl.h>
#include <stdlib.h>
#include <acldev.h>
#include <aclstr.h>
#include <ctype.h>
#include <actutil.h>

/** /#define DEBUG_VSENTRY*/
#ifdef DEBUG_VSENTRY
#define DEBUG_95
#endif

#include <define.h>
#include <tran.h>
#include <entry.h>
#include <gds.h>
#include <card.h>
#include <msg.h>
#include <msgfuncs.h>
#include <ui.h>
#include <util.h>
#include <fields.h>
#include <spdebug.h>
#include <tct.h>
#include <logo.h>
#include <format.h>
#include <codesec.h>

#define DIGITS_PER_SEPARATOR    3

int inTwoStrings = 0;       /* The following allows the programmer to pass */
char szTempMsg1[MESSAGE_SIZE + 1]; /* just one parameter with pchGetMsg     */
char szTempMsg2[MESSAGE_SIZE + 1];
char szTempMsg3[MESSAGE_SIZE + 1];

static void vdInitKeypad(int);
static void vdEntryDisplayAt(WIN_INFO* wi8x21Win,int inCol,int inRow,char* szDispBuf,int inClear);              
static KeyboardInfo Keypad;

/******************************************************************************
 *                          Keyboard related functions.                       *
 ******************************************************************************/

static void vdInitKeypad(int inTermType) {
    static int sinKeysSet = 0;

    if (!sinKeysSet) {
        sinKeysSet = 1; /* do it once */

        if (inTermType == TERMINAL_OMNI_3200) {
            /*
             *  This init block NOT 
             *  applicable to other displays. 
             */
            // Screen addressable selection keys
            Keypad.inChoiceKeyCodesOne[0] = (int) KEY_e;
            Keypad.inChoiceKeyCodesOne[1] = (int) KEY_f;
            Keypad.inChoiceKeyCodesOne[2] = (int) KEY_g;
            Keypad.inChoiceKeyCodesOne[3] = (int) KEY_h;

            Keypad.lChoiceKeyMapsOne[0] = (long) KM_e;    
            Keypad.lChoiceKeyMapsOne[1] = (long) KM_f;    
            Keypad.lChoiceKeyMapsOne[2] = (long) KM_g;    
            Keypad.lChoiceKeyMapsOne[3] = (long) KM_h;  

            // Function HOT keys
            Keypad.inChoiceHotKeyCodesOne[0] = (int) KEY_a;
            Keypad.inChoiceHotKeyCodesOne[1] = (int) KEY_b;
            Keypad.inChoiceHotKeyCodesOne[2] = (int) KEY_c;
            Keypad.inChoiceHotKeyCodesOne[3] = (int) KEY_d;

            Keypad.lChoiceHotKeyMapsOne[0] = (long) KM_a;    
            Keypad.lChoiceHotKeyMapsOne[1] = (long) KM_b;    
            Keypad.lChoiceHotKeyMapsOne[2] = (long) KM_c;    
            Keypad.lChoiceHotKeyMapsOne[3] = (long) KM_d;
        }
    }
}


/********************************************************************************************* 
* @func int | inChooseOneDefault 
*
*                The user must choose an option from the display.
*                Note that the first two parameters are char* and can be a
*                constructed string (i.e. user created) or can be obtained
*                from the message file. For the latter it is recommended that
*                the routine pchGetMsg is used e.g. pchGetMsg(ERR_MSG).
*                The third parameter is an int and is the index into the message
*                file. This message must be of the format "opt1~opt2~opt3~opt4"
*                i.e. up to 4 options separated by a '~'.
*                The final parameter is the number of options in inChoiceMsg
*
* @parm char | *pchFirstMsg | 
*          Pointer to first message string
*
* @parm char | *pchSecondMsg | 
*          Pointer to secone message string
*
* @parm char | *pchChoiceMsg | 
*          Message index into message file
*
* @parm int | inNumChoices | 
*          Number of choices in pchChoiceMsg
*
* @rdesc return values.
* @flag int | index of choice 
* @end
**********************************************************************************************/

int inChooseOneDefault(char* pchFirstMsg,char* pchSecondMsg,char* pchChoiceMsg,int inNumChoices,PFI_VOID pinDisplayFunc) {
    char szDispBuf[4][MESSAGE_SIZE + 1]; 

    int inFirstKey = 0;
    int inLastKey = 0;
    int inIndex = 0;
    long lValidBits = (long) KM_ESC;
    long lValid = (long) 0;
    signed long lAnswer = (long) 0;

    /*LOG_PRINTFF((0x8L, "--inChooseOneDefault--"));*/

    memset(szDispBuf, NULL_CH, sizeof(szDispBuf));

    vdInitKeypad(obDisp.inTerminalType);

    inTwoStrings = 0; /* GLOBAL */

    if (inNumChoices == 2) {
        /*inFirstKey = 1; ORIG LINE */
        /*
         *  9-2-98 mod: Two
         *  choices; per Mktg,
         *  start choices at
         *  first (top) key.
         *  Also modified:
         *  vdPrepare3200LineChoice()
         */
        inFirstKey = 0;
    } else
        inFirstKey = 0;

    inLastKey = inFirstKey + inNumChoices - 1;

    /* Set the mask to the screen addressable keys for the default */
    for (inIndex = inFirstKey; inIndex <= inLastKey; ++inIndex) {
        lValidBits |= Keypad.lChoiceKeyMapsOne[inIndex];
    }

    vdFlushKeyboardBuffer();

    if (pchChoiceMsg[0]) {
        vdPrepare3200LineChoice(pchChoiceMsg, inNumChoices, szDispBuf);
        vdCreateOptWin3200(szDispBuf);  /* right-side keys.... */
    }

    if (pinDisplayFunc == NULL_PFI) {
        /* 
         * cleanup any leftover
           * text here....
         */
        if (pchFirstMsg || pchSecondMsg)
            vdClearNonTitleLines();

        if (pchFirstMsg) {
            /*
               *   First Message: goes on left of 3200 screen
               */
            if (strlen(pchFirstMsg) > (unsigned) obDisp.inCharsPerRow)
                pchFirstMsg[obDisp.inCharsPerRow] = NULL_CH;

            vdDisplayAt(obDisp.inHomeCol, obDisp.inFirstLineCOne, pchFirstMsg, NO_CLEAR);
        }

        if (pchSecondMsg) {
            /*
               *   Second Message: goes on left of 3200 screen
             */
            if (strlen(pchSecondMsg) > (unsigned) obDisp.inCharsPerRow)
                pchSecondMsg[obDisp.inCharsPerRow] = NULL_CH;

            vdDisplayAt(obDisp.inHomeCol, obDisp.inSecondLineCOne, pchSecondMsg, NO_CLEAR);
        }
    } else
        pinDisplayFunc(); 


    while (TRUE) {
        lValid = 0L;

        lAnswer = inWaitKey(inGetIdleTimeOut());

       for (inIndex = inFirstKey; inIndex <= inLastKey; ++inIndex) {
            if (lAnswer == Keypad.inChoiceKeyCodesOne[inIndex])
                lValid = Keypad.lChoiceKeyMapsOne[inIndex] & lValidBits;
        }

	 if (!lValid)
            for (inIndex = 0; inIndex < NUM_HOTKEYS; ++inIndex) {
                if (lAnswer == Keypad.inChoiceHotKeyCodesOne[inIndex])
                    lValid = Keypad.lChoiceHotKeyMapsOne[inIndex] & obDisp.lnChooseOneHotKeys;
            }

	 if (lAnswer == KEY_CANCEL || lValid) // BJD: KEY_CLR -> KEY_CANCEL
            break;
        else
            ERR_BEEP();
    }

    vdDestroyOptWin3200();  /* reset to prior.... */

    vdClearNonTitleLines();

    for (inIndex = inFirstKey; inIndex <= inLastKey; ++inIndex) {
        if (lAnswer == Keypad.inChoiceKeyCodesOne[inIndex])
            return(inIndex - inFirstKey + 1);
    }

    for (inIndex = 0; inIndex <= 4; ++inIndex) {
        if (lAnswer == Keypad.inChoiceHotKeyCodesOne[inIndex])
            return(inIndex + 5);
    }
    return(VS_ESCAPE);
}

/*-----------------------------------------------------------------------------
* Routine Name : vdFormatChoiceStr()
* Description  : Copies up to inMaxPrmptSize characters from source buf to
*                destination buf (or up to the NULL_CH in source buf). Pads
*                spaces onto destination buf up to inMaxFieldWidth and
*                appends a NULL_CH.
* Parameters   : pchDst = pointer to destination buffer
*                pchSrc = pointer to source buffer
*                inMaxPrmptSize  = Maximum Prompt size
*                inMaxFieldWidth = Maximum field width
* Returns      :
* Notes        :
*-----------------------------------------------------------------------------
*/
void vdFormatChoiceStr(char* pchDst,char* pchSrc,int inMaxPrmptSize,int inMaxFieldWidth) {
    inMaxPrmptSize--;
    while ((*pchSrc != '\0') && (*pchSrc != '~') && (inMaxPrmptSize-- > 0)) {
        *(pchDst++) = *(pchSrc++);
        inMaxFieldWidth--;
    }

    while (inMaxFieldWidth-- > 0) {
        *(pchDst++) = ' ';
    }
    *pchDst = '\0';
}

int inEnterNumber(WIN_INFO* psr_wi8x21Win,char* szResponseString,int inMaxChars,char* szCurSym,char* szAmtFormat) {
    int inCharsEntered,
    inInitialKeyHit = TRUE;
    int inFieldVisibleWidth;
    int inResult;
    char chChar;
    char szInternalBuffer[FORMATTED_AMOUNT_SIZE + 1];
    char szLocBuf[1 + 1];
    VS_BOOL fNegativeValue;

    /** /pdebug(("--inEnterNumber--"));*/

    memset(szLocBuf, NULL_CH, sizeof(szLocBuf));
    inFieldVisibleWidth = psr_wi8x21Win->inRight - psr_wi8x21Win->inLeft + 1;
    strlcpy(szInternalBuffer, szResponseString, FORMATTED_AMOUNT_SIZE);
    if (szInternalBuffer[0] == '-')
        fNegativeValue = VS_TRUE;
    else
        fNegativeValue = VS_FALSE;
    purge_char(szInternalBuffer, ',');//chRadixDelimiter);
    purge_char(szInternalBuffer, '.');//chSeparatorDelimiter);
    purge_char(szInternalBuffer, '-');
    inCharsEntered = strlen(szInternalBuffer);

    formatAmt(szResponseString, szInternalBuffer, szCurSym, szAmtFormat, VS_FALSE);
    vdEntryDisplayAt(psr_wi8x21Win, inFieldVisibleWidth - strlen(szResponseString) + 1, obDisp.inTitleLine, szResponseString, CLR_EOL);

    while (1) {
        chChar = (char) inWaitKey(inGetIdleTimeOut());

        if (chChar == KEY_CR || chChar == KEY_CANCEL)
            break;

        /** /pdebug(("chChar = %02Xh", chChar));*/
        /** /pdebug(("inCharsEntered = %d", inCharsEntered));*/

        if (inInitialKeyHit && inCharsEntered && (isdigit(chChar))) {
            /** /pdebug(("Clearing Value"));*/
            szInternalBuffer[0] = chChar;
            szInternalBuffer[1] = 0;
            formatAmt(szResponseString, szInternalBuffer, szCurSym, szAmtFormat, VS_FALSE);
            vdEntryDisplayAt(psr_wi8x21Win, obDisp.inHomeCol, obDisp.inTitleLine, szLocBuf, CLR_EOL); /* Clear any old entry off display */
            vdEntryDisplayAt(psr_wi8x21Win, inFieldVisibleWidth - strlen(szResponseString) + 1, obDisp.inTitleLine, szResponseString, CLR_EOL);
            inCharsEntered = 0;
        }

        szInternalBuffer[inCharsEntered] = chChar;
        switch (chChar) {
        case    KEY_BS:
            if (inCharsEntered) {
                vdEntryDisplayAt(psr_wi8x21Win, inFieldVisibleWidth - strlen(szResponseString) + 1, obDisp.inCharsPerColumn - 1, "  ", NO_CLEAR);
                --inCharsEntered;
            } else
                vdBeep();
            inInitialKeyHit = FALSE;
            break;

            // BJD: KEY_CLR processing (begin)
        case    KEY_CLR:
            if (inCharsEntered) {
                szInternalBuffer[0] = '\0';
                inCharsEntered = 0;
                formatAmt(szResponseString, szInternalBuffer, szCurSym, szAmtFormat, VS_FALSE);
                vdEntryDisplayAt(psr_wi8x21Win, obDisp.inHomeCol, obDisp.inTitleLine, szLocBuf, CLR_EOL); /* Clear any old entry off display */
                vdEntryDisplayAt(psr_wi8x21Win, inFieldVisibleWidth - strlen(szResponseString) + 1, obDisp.inTitleLine, szResponseString, CLR_EOL);
            } else    // No characters entered yet
                vdBeep();
            break;
            // BJD: KEY_CLR processing (end)

        case    '0':
            if (inCharsEntered == 0)
                --inCharsEntered;

        case    '1':
        case    '2':
        case    '3':
        case    '4':
        case    '5':
        case    '6':
        case    '7':
        case    '8':
        case    '9':
            if (inCharsEntered < inMaxChars)
                ++inCharsEntered;
            else
                vdBeep();
            inInitialKeyHit = FALSE;
            break;

        case    KEY_ALP:
            /** /pdebug(("KEY_ALP"));*/
            if (fNegativeValue == VS_FALSE) {
                if (inCharsEntered < inMaxChars)
                    fNegativeValue = VS_TRUE;
                else
                    vdBeep();
            } else {
                fNegativeValue = VS_FALSE;
                vdEntryDisplayAt(psr_wi8x21Win, inFieldVisibleWidth - strlen(szResponseString) + 1, obDisp.inCharsPerColumn - 1, "  ", NO_CLEAR);
            }
            inInitialKeyHit = FALSE;
            break;

        default:
            vdBeep();
        }
        szInternalBuffer[inCharsEntered] = '\0';
        /** /pdebug(("szInternalBuffer = %s", szInternalBuffer));*/

        formatAmt(szResponseString, szInternalBuffer, szCurSym, szAmtFormat, VS_FALSE);
        vdEntryDisplayAt(psr_wi8x21Win, inFieldVisibleWidth - strlen(szResponseString) + 1, obDisp.inTitleLine, szResponseString, CLR_EOL);
        /** /pdebug(("szResponseString = %s", szResponseString));*/
    }
    /** /pdebug(("chChar = %02Xh", chChar));*/

    //if (!gu_clr_state()) -- key is already read from kbd buffer in inWaitKey() so is not pending anymore
    if (chChar != KEY_CANCEL) {
        formatAmt(szResponseString, szInternalBuffer, "", szAmtFormat, VS_FALSE);   // Reformats output with no currency for processing!
        inResult = strlen(szResponseString);
    } else
        inResult = VS_ESCAPE;

    /** /pdebug(("inResult = %d", inResult));*/
    return(inResult);
}

int inEnterWithMessage(long lnMessageNumber,VS_BOOL fScrollDisplay,char* szResponseString,int inDataType,int inMaxChars,int  (*inValidator) (char* szResponseString)) {
    char szMessage[MESSAGE_SIZE + 1];

    /**/pdebug(("--inEnterWithMessage(%ld)--", lnMessageNumber));/**/

    vdGetMessageFromFile(lnMessageNumber, szMessage);

    *szResponseString = NULL_CH;

    return (inEnterWithStrDefault(lnMessageNumber, ((lnMessageNumber != EMPTY_STR_ERR_MSG) ? szMessage : NULL_CH), fScrollDisplay, szResponseString, inDataType, inMaxChars, inValidator));
}

int inEnterWithMessageDefault(long lnMessageNumber,VS_BOOL fScrollDisplay,char* szResponseString,int inDataType,int inMaxChars,int (*inValidator) (char* szResponseString)) {
    char szMessage[MESSAGE_SIZE + 1];

    /**/pdebug(("--inEnterWithMessage(%lx)--", lnMessageNumber));/**/

    vdGetMessageFromFile(lnMessageNumber, szMessage);

    return (inEnterWithStrDefault(lnMessageNumber, ((lnMessageNumber != EMPTY_STR_ERR_MSG) ? szMessage : NULL_CH), fScrollDisplay, szResponseString, inDataType, inMaxChars, inValidator));
}


/*-----------------------------------------------------------------------------
* Routine Name : inEnterWithStrDefault()
* Description  : 
* Parameters   : 
* Returns      :
* Notes        :
*    Modification History :
*    #     Date     Who                     Description
*  ----- -------- ----------    ---------------------------------------------
*    1     ?          ?                     Creation
*    2   10/02/96 Pat_G1        Changed NO_CLEAR to CLR_LINE if BS and
*                               changed NO_CLEAR to CLR_EOL for display to get
*                               rid of extra characters on the O470.
*    3   12/17/96 Paula_J1      Modified so that if input string length is equal to
*                               screen width, the prompt will not get overwritten
*    4   12/18/96 Pat_G1        Changed CLR_LINE to NO_CLEAR if BS to avoid
*                               erasing all the *'s when BS is hit for a password.
*    5   12/19/96 Pat_G1        Modified Change #3 so that if the input string is 
*                               longer than the visible width of the screen, the prompt
*                               will not be overwritten.
*    6   08/01/97 KC_C1         if user swipe card, set inResult = VS_ERR, 
*                               take out one vdDisplayMessageFromFile because
*                               the index is not set.
*    7   08/11/97 KC_C1         if timeout  set gu_clr_state = TRUE;
*    8   08/27/97 KC_C1         add break in case of inValidResponse = VS_ERR
*    9   06/17/98 Kevin_V1      This function displays existing (default) data in response 
*                               string if any exists.  Name changed from inEnterWithString().
*                               Please not No new parameters accompanied this modification.
*-----------------------------------------------------------------------------
*/

void vdClearEntryLines(int inTermCharsPerRow) {
    /*
     *      Clear Prompt and Entry lines.
     */
    if (obDisp.blActionFontASC8x21)
        vdClear_8X21_Window(obDisp.inHomeCol, obDisp.inInputLine, inTermCharsPerRow, obDisp.inInputLine + 1);
    else {
        int inDummyCol;
        int inInputLine = obDisp.inInputLine;

        vdCalculateCoord(GRID_4x8_TO_8x21, &inDummyCol, &inInputLine);
        vdClear_8X21_Window(obDisp.inHomeCol, inInputLine - 1, inTermCharsPerRow, inInputLine + 3);
    }
}

static void vdEntryDisplayAt(WIN_INFO* wi8x21Win,int inCol,int inRow,char* szDispBuf,int inClear) {
    int inLeft,
    inTop,
    inRight,
    inBottom;
    char szFontName[FILENAME_SIZE + 1];

    if (obDisp.blActionFontASC8x21)
        vdDisplayAt(inCol, inRow, szDispBuf, inClear);
    else {
        wherewin(&inLeft, &inTop, &inRight, &inBottom);
        get_font(szFontName);
        set_font(ASC8X21_VFT);
        window(wi8x21Win->inLeft, wi8x21Win->inTop, wi8x21Win->inRight, wi8x21Win->inBottom);
        vdDisplayAt(inCol, inRow, szDispBuf, inClear);
        set_font(szFontName);

        window(inLeft, inTop, inRight, inBottom);
    }
    return;
}        

int inEnterWithStrDefault(long lnMsgId,char* szPromptString,VS_BOOL fScrollDisplay,char* szResponseString,int inDataType,int inMaxChars,int (*inValidator) (char* szResponseString)) {
    char szAst[1 + 1];
    char szLocBuf[1 + 1];

    int inLeft,
    inTop,
    inRight,
    inBottom,
    inResult = 0;
    int inValidResponse;
    int inChar,
    inCharOffset = 0,
    inNewLine = FALSE,
    inCharsPastDisplay;
    int inFieldVisibleWidth;
    VS_BOOL fNegativeValue = FALSE,
    fInitialKeyPress = TRUE;
    int inTermCharsPerRow;
    int inPromptTermCharsPerRow;
    int inEntryRow;
    WIN_INFO wiCur8x21Win;

    szAst[0] = '*'; szAst[1] = 0;
    strcpy(szLocBuf, " ");

    /*
     *  determine if entry is on current
     *  or current+1 line....
     */
    inEntryRow = obDisp.inInputLine;
    vdSetEntryRow(&inEntryRow);
    inPromptTermCharsPerRow = inTermCharsPerRow = inGetRowLim();
    if (!obDisp.blActionFontASC8x21)
        vdCalculateCoord(GRID_4x8_TO_8x21, &inTermCharsPerRow, &inEntryRow);
    inFieldVisibleWidth = inTermCharsPerRow;

    wherewin(&inLeft, &inTop, &inRight, &inBottom);
    if (szPromptString)
        vdScrollDataEntry(fScrollDisplay);

    if ((!obDisp.blCfigEdit) && (!obDisp.blEntryNextLine)) {
        /*
         *  not config edit, or entry on the
         *  next line, so apply normal rule...
         */
        if (szPromptString)
            inFieldVisibleWidth = inTermCharsPerRow - strlen(szPromptString);
    }

    if (inMaxChars < inFieldVisibleWidth)
        inFieldVisibleWidth = inMaxChars;

    do {
        if (szPromptString) {
            /*
                 *      Clear Entry Lines & Display Prompt
                 */
            //BT_TRACE ('I', szPromptString);
            vdClearEntryLines(inTermCharsPerRow);
            vdDisplayAt(obDisp.inHomeCol, obDisp.inInputLine, szPromptString, NO_CLEAR);
            window(inLeft, inTop, inRight, inBottom);
        }

        /*
         *      Handle existing data in response buffer.
         */
        fInitialKeyPress = TRUE;

        /* Setup entry window */
        wiCur8x21Win.inLeft = inTermCharsPerRow - inFieldVisibleWidth + 1;
        wiCur8x21Win.inTop = wiCur8x21Win.inBottom = inEntryRow;
        wiCur8x21Win.inRight = inTermCharsPerRow ;
        if (obDisp.blActionFontASC8x21)
            window(wiCur8x21Win.inLeft, wiCur8x21Win.inTop, wiCur8x21Win.inRight, wiCur8x21Win.inBottom);

        if (*szResponseString) {
            inCharOffset = strlen(szResponseString);
            if ((inFieldVisibleWidth <= inMaxChars) && (inCharOffset > inFieldVisibleWidth)) {
                inCharsPastDisplay = inCharOffset - inFieldVisibleWidth;
                vdEntryDisplayAt(&wiCur8x21Win, obDisp.inHomeCol, obDisp.inTitleLine, szResponseString + inCharsPastDisplay, NO_CLEAR);
            } else
                vdEntryDisplayAt(&wiCur8x21Win, inFieldVisibleWidth - inCharOffset + 1, obDisp.inCharsPerColumn - 1, szResponseString, CLR_EOL);
        }

        while (((inChar = inWaitKey(inGetIdleTimeOut())) != KEY_CR) && (inChar != KEY_CANCEL)) // BJD: KEY_CLR -> KEY_CANCEL
        {
            if (fInitialKeyPress) {
                *szResponseString = NULL_CH;
                inCharOffset = 0;
                vdEntryDisplayAt(&wiCur8x21Win, obDisp.inHomeCol, obDisp.inCharsPerColumn - 1, szResponseString, CLR_EOL);
            }
            fInitialKeyPress = FALSE;
            switch (szResponseString[inCharOffset] = (char) inChar) {
            case KEY_BS:
                if (inCharOffset) {
                    if (inFieldVisibleWidth >= inCharOffset) {
                        //vdDisplayAt(inFieldVisibleWidth - inCharOffset + 1, obDisp.inTitleLine, szLocBuf, NO_CLEAR );                                    
                        vdEntryDisplayAt(&wiCur8x21Win, inFieldVisibleWidth - inCharOffset + 1, obDisp.inTitleLine, " ", NO_CLEAR);
                    }

                    --inCharOffset;
                } else
                    vdBeep();
                break;

                // BJD: KEY_CLR processing (begin)
            case KEY_CLR:
                if (inCharOffset) {
                    szResponseString[0] = '\0';
                    inCharOffset = 0;
                    vdEntryDisplayAt(&wiCur8x21Win, obDisp.inHomeCol, obDisp.inCharsPerColumn - 1, szResponseString, CLR_EOL);
                } else    // No characters entered yet
                    vdBeep();
                break;
                // BJD: KEY_CLR processing (end)

            case KEY_a:
            case KEY_b:
            case KEY_c:
            case KEY_d:
            case KEY_e:
            case KEY_f:
            case KEY_g:
            case KEY_h:
                vdBeep();
                continue;

            case KEY_ALP:
                if ((inDataType == INPUT_ALNUMS) || (inDataType == INPUT_ALNUMS_PWD)) {
                    if (inCharOffset) {
                        inChar = chGetAlphaKey(szResponseString[inCharOffset - 1]);
                        szResponseString[inCharOffset - 1] = (char) inChar;
                    } else
                        vdBeep();
                } else {
                    if (fNegativeValue == VS_FALSE) {
                        if (strlen(szResponseString) < (unsigned) inMaxChars)
                            fNegativeValue = VS_TRUE;
                        else
                            vdBeep();
                    } else {
                        fNegativeValue = VS_FALSE;
                        vdEntryDisplayAt(&wiCur8x21Win, inFieldVisibleWidth - inCharOffset + 1, obDisp.inTitleLine, "  ", NO_CLEAR);
                    }
                }
                break;

            default:
                if ((inCharOffset < inMaxChars) && (((inDataType == INPUT_FLAG) && ((inChar == '0') || (inChar == '1'))) || ((inDataType != INPUT_FLAG) && ((inDataType != INPUT_NUMS && inDataType != INPUT_NUMS_PWD) || ((inChar != KEY_STR) && (inChar != KEY_PND))))))
                    ++inCharOffset;
                else
                    vdBeep();
            }
            szResponseString[inCharOffset] = '\0';
            if ((inDataType == INPUT_NUMS_PWD) || (inDataType == INPUT_ALNUMS_PWD)) {
                if (inChar != KEY_BS)
                    vdEntryDisplayAt(&wiCur8x21Win, inFieldVisibleWidth - inCharOffset + 1, obDisp.inTitleLine, szAst, NO_CLEAR);
            } else {
                /* pj1 */   
                if ((inFieldVisibleWidth <= inMaxChars) && (inCharOffset > inFieldVisibleWidth)) {
                    inCharsPastDisplay = inCharOffset - inFieldVisibleWidth;
                    vdEntryDisplayAt(&wiCur8x21Win, obDisp.inHomeCol, obDisp.inTitleLine, szResponseString + inCharsPastDisplay, NO_CLEAR);
                } else
                    vdEntryDisplayAt(&wiCur8x21Win, inFieldVisibleWidth - inCharOffset + 1, obDisp.inCharsPerColumn - 1, szResponseString, CLR_EOL);
            }
        }
        szResponseString[inCharOffset] = '\0';
        if (inChar == KEY_CANCEL)    // BJD: KEY_CLR -> KEY_CANCEL
            inResult = VS_ESCAPE;
        else
            inResult = inCharOffset;
        window(inLeft, inTop, inRight, inBottom);

        inValidResponse = inResult;
        if (inValidResponse >= 0) {
            if (inValidator) {
                //vdResetEntryFont (VS_FALSE);
                if ((inValidResponse = (*inValidator) (szResponseString)) == VS_ERR) {
                    vdDisplayMessageFromFile(lnGGErrorMessage(), WARNING_MSG);
                    vdSGErrorMessage(0L);
                    *szResponseString = NULL_CH;
                }
                //vdSetEntryFont (VS_FALSE);
            }
            /** /pdebug(("inResult=%d", inResult));*/
        }
    } while (inValidator && (inValidResponse == VS_ERR));

    /** /pdebug(("szResponseString=%s", szResponseString));*/
    window(inLeft, inTop, inRight, inBottom);
    if (!obDisp.blEntryNextLine)
        vdClearStatusMessage();

    if (obDisp.blCfigEdit) {
#if 0
    /* remove prompt and entry */
    window(obDisp.inHomeCol, (inEntryRow-1), inTermCharsPerRow, inEntryRow);
    clrscr();
    window(inLeft, inTop, inRight, inBottom);
#endif
        vdClearEntryLines(inTermCharsPerRow);
        window(inLeft, inTop, inRight, inBottom);
    }

    if (obDisp.blEntryNextLine)
        obDisp.blNextLineCleanup = VS_TRUE;
    else
        obDisp.blNextLineCleanup = VS_FALSE;

    vdClrNextLineEntry(); /* done with this for now */
    //vdResetEntryFont (VS_FALSE);
    return(inResult);
}


/*-------------------------------------------------------------------------
    Function :    vdSetEntryRow
    Description : Determines proper row for entry after message,
                  which could be the same row or the next row
                  (for the 3200 confrec editing).
    Parameters :
    Returns :
    Globals :
    Notes :
    Modification History :
    #     Date      Who                     Description
  ----- -------- ---------- ---------------------------------------------
    0   08/17/98 EW_1       Created.
--------------------------------------------------------------------------*/
void vdSetEntryRow(int* pInRow) {
    if (pInRow) {
        if ((obDisp.blCfigEdit) || (obDisp.blEntryNextLine))
            (*pInRow) = obDisp.inCharsPerColumn;
    }
}

/*
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      1   02/03/98 Kevin_v1     Modified to use SPA_MESSAGE_FILE.
 */

void vdReset_pchGetMsg(void) {
    inTwoStrings = 0;       // since pchGetMsg () was used outside of inChooseOne...
}

char* pchGetMsg(long lnMsgIdx) {
    /** /pdebug(("--pchGetMsg--"));*/
    if (inTwoStrings == 0) {
        *szTempMsg1 = NULL_CH;
        vdGetMessageFromFile(lnMsgIdx, szTempMsg1);
        inTwoStrings++;
        return(szTempMsg1);
    } else if (inTwoStrings == 1) {
        *szTempMsg2 = NULL_CH;
        vdGetMessageFromFile(lnMsgIdx, szTempMsg2);
        inTwoStrings++;
        return(szTempMsg2);
    } else {
        *szTempMsg3 = NULL_CH;
        vdGetMessageFromFile(lnMsgIdx, szTempMsg3);
        return(szTempMsg3);
    }
}


/*-------------------------------------------------------------------------
    Function :    inGetManualApproval
    Description : Enter approval code from call to voice center
    Parameters :
    Returns :
    Notes :
--------------------------------------------------------------------------*/

int inGetManualApproval(char* pchAuthCode,int inAuthCodeSize) {
    int inRetVal;
    VS_BOOL fFirstOne = VS_TRUE;
    unsigned long ulTimerCount;

    /** /pdebug(("--inGetManualApproval--"));*/


    vdFlushKeyboardBuffer();
    vdClearNonTitleLines();

    do {
        ulTimerCount = set_itimeout(NO_CLOCK_HANDLE PROMPT_DELAY_SECONDS, TM_SECONDS);
        if (fFirstOne == VS_TRUE) {
            vdDispMsgAt(REFERRAL_MSG, obDisp.inHomeCol, obDisp.inInputLine, CLR_EOL);
            fFirstOne = VS_FALSE;
        } else {
            vdDispMsgAt(CALL_VOICE_CENTER_MSG, obDisp.inHomeCol, obDisp.inStatusLine, CLR_EOL);
            fFirstOne = VS_TRUE;
        }
    } while (!KBHIT());

    if (act_kbd_pending_test(KEY_CANCEL)) {
        vdSetTranError(TXN_CANCELLED);
        return (VS_ESCAPE);
    }

    vdFlushKeyboardBuffer();

    inRetVal = inEnterWithMessage(AUTH_CODE_MSG, VS_FALSE, pchAuthCode, INPUT_ALNUMS, inAuthCodeSize, inValidateString);
    if (inRetVal <= 0)
        return(VS_ERR);
    else
        return(VS_TRUE);
}

/********************************************************************************************* 
* @func int | inValInvoiceEntry |
*             Validates Invoice Number entry for Void, Review, etc..
*
* @parm char * | szString | 
*       Input szString
*
* @rdesc 
* @flag int | VS_SUCCESS 
* @flag int | VS_ERR 
* @end
**********************************************************************************************/

int inValInvoiceEntry(char* szString) {
    if (strlen(szString) > 0 && (str2long(szString)) == 0L) {
        vdSGErrorMessage(INVALID_ENTRY_MSG);
        return (VS_ERR);
    }

    return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func int | inValStringMinLength |
*             Validates Minimum string length using Display Object Length Variable
              which must be loaded prior to validation invocation.
*
* @parm char * | szString | 
*       Input szString
*
* @rdesc 
* @flag int | VS_SUCCESS 
* @flag int | VS_ERR 
* @end
**********************************************************************************************/

int inValStringMinLength(char* szString) {
    if (strlen(szString) < obDisp.inStringMinLength) {
        vdSGErrorMessage(INVALID_ENTRY_MSG);
        return (VS_ERR);
    }

    return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func int | inValidateString |
*             Validates against ENTER Key only entry.
*
* @parm char * | szInputPwd | 
*       Input password
*
* @rdesc 
* @flag int | VS_SUCCESS 
* @flag int | VS_ERR 
* @end
**********************************************************************************************/

int inValidateString(char* szString) {
    if (strlen(szString) == 0) {
        vdSGErrorMessage(INVALID_ENTRY_MSG);
        return (VS_ERR);
    }

    return(VS_SUCCESS);
}

/*---------------------------------------------------------------------------
    Function :    inZipCodeValidator
    Description : This function makes sure the zip code length is 5, 9, or 0.
    Parameters :
    Returns :       VS_ERR, or VS_SUCCESS
    Globals :     none
    Notes :
    Modification History :
      #     Date      Who                     Description
    ----- -------- ----------  ---------------------------------------------
      1  08/25/96  Pat_G1      Creation.
      2  08/25/96  Pat_G1      Don't allow '#' or '*' entry.
      3  09/18/96  Monique_B1  Added error message
 ---------------------------------------------------------------------------*/

int inZipCodeValidator(char* pszZipCode) {
    if (((strlen(pszZipCode) == 5) || (strlen(pszZipCode) == 9) || (strlen(pszZipCode) == 0)) && ((strchr(pszZipCode, '*') == NULL_CH) && (strchr(pszZipCode, '#') == NULL_CH)))
        return(VS_SUCCESS);
    else {
        vdBeep();
        vdSGErrorMessage(INVALID_ENTRY_MSG);
        return(VS_ERROR);
    }
}

int inValidFixedResponse(char* szFixedResponse) {
    int inTemp;

    inTemp = atoi(szFixedResponse);
    if ((inTemp < 2) || (inTemp > 99)) {
        vdSGErrorMessage(NUM_INST_ERR_MSG);
        return(VS_ERR);
    }
    return(VS_SUCCESS);
}

int inValidVarResponse(char* szVarResponse) {
    int inTemp;

    inTemp = atoi(szVarResponse);
    if ((inTemp != 3) && (inTemp != 6) && (inTemp != 10)) {
        vdSGErrorMessage(NUM_INST_ERR_MSG);
        return(VS_ERR);
    }
    return(VS_SUCCESS);
}


int ENTRY_CODE_CHECK(char* a,char* b,short* c,char* d,unsigned char* e) {
    GET_VER(a, b, c, d, e);
    return 1;
}

#undef VSENTRY_C

